package cn.hy.file.upload.controller;

import cn.hy.file.upload.config.FIleUploadProperties;
import cn.hy.file.upload.service.FileUploadService;
import cn.hy.file.upload.vo.FileInfo;
import cn.hy.file.upload.vo.FileInfoVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 前端：需要将文件file.slice()成多个文件块，并计算每一块的md5值，每次请求上传都是传一个小文件块。
 * 后端: 需要接收每次上传的文件块并保存文件块的信息（比如md5), 如果已经上传则跳过；最后等所有文件上传完成之后，将所有的文件块合并成一个大文件。
 */
@Slf4j
@RestController
public class FileUploadController {

    @Resource
    FileUploadService fileUploadService;

    @Resource
    FIleUploadProperties fIleUploadProperties;


    @PostMapping("upload")
    public void upload(@RequestParam(value = "file") MultipartFile file, FileInfo fileInfo) throws Exception {
        if (file.isEmpty()) {
            return;
        }
        // 上传oss
        // 本地  搞台服务器存文件  而不是写到包下 this.getClass().getResource("/").getPath()
        String storePath = fIleUploadProperties.getStorePath();
        //uid 防止文件名重复,又可以作为文件的唯一标识
        String fullPath = this.getClass().getResource("/").getPath() + fileInfo.getMd5() + "." + fileInfo.getSliceIndex();
        File dest = new File(fullPath);
        file.transferTo(dest);
        log.info("文件分片 {} 保存完成", fileInfo.getSliceIndex());
        //开始保存索引分片信息 bu不存在就新加 存在就修改索引分片

        // merge 不在这里做，从数据库获取下载数据，判断是否分片是否上传完了， 下载的时候去合并文件，并删除临时文件
        if (fileInfo.getSliceIndex().equals(fileInfo.getTotalSlice() - 1)) {
            // merge(fileInfo);
            // deleteTempFile(fileInfo);
        }
    }

    private void deleteTempFile(FileInfo fileInfo) {
        try {
            Files.delete(Paths.get(Objects.requireNonNull(this.getClass().getResource("/")).getPath(),
                    fileInfo.getMd5() + "." + fileInfo.getSliceIndex()));
        } catch (IOException e) {
            log.error("delete file error", e);
        }
    }


    private void merge(FileInfo fileInfo) {
        byte[] buffer = new byte[10 * 1024];
        int len = 0;
        try (RandomAccessFile osFileSave = new RandomAccessFile(Objects.requireNonNull(this.getClass().getResource("/")).getPath()
                + fileInfo.getFileName(), "rw")) {
            for (int i = 0; i < fileInfo.getTotalSlice() - 1; i++) {
                String fullPath = this.getClass().getResource("/").getPath() + fileInfo.getMd5() + "." + fileInfo.getSliceIndex();
                try (BufferedInputStream bis = new BufferedInputStream(Files.newInputStream(Paths.get(fullPath)))) {
                    while ((len = bis.read(buffer)) != -1) {
                        osFileSave.write(buffer, 0, len);
                    }
                }
            }
            log.info("file merge finish ");
        } catch (IOException e) {
            log.error("file merge fail ..", e);
        }
    }


    /**
     *
     * @param fileName 文件唯一标识
     * @return
     */
    @GetMapping("/chunks")
    public ResponseEntity<FileInfoVo> chunks(@RequestParam String fileName) {

        // List<FileInfo> fileInfoList = fileUploadService.findByFileName();

        List<FileInfo> fileInfoList = new ArrayList<>();
        FileInfo fileInfo = new FileInfo();
        fileInfo.setMd5("11");
        fileInfo.setSliceIndex(0);
        fileInfoList.add(fileInfo);
        FileInfoVo fileInfoVo = FileInfoVo.builder()
                        .fileName(fileName)
                        .chunkList(fileInfoList.stream()
                        .map(FileInfo::getSliceIndex)
                        .collect(Collectors.toList()))
                .build();
        return ResponseEntity.ok(fileInfoVo);
    }


    @GetMapping("/checkUpload")
    public ResponseEntity<Boolean> checkUpload(@RequestParam String md5) {
        // 查看数据库是否存在 这个分片
        // fileUploadService.checkUpload(md5);
        return ResponseEntity.ok(false);
    }


}
